﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using Plossum.CommandLine;
using Syno.Core.Xml;
using XmlReader = System.Xml.XmlReader;

namespace Syno.Cmd
{
    class Program
    {
        [STAThread]
        private static int Main(string[] args)
        {
            XmlConfigurator.Configure();
            var programParams = new ProgramParams();
            var parser = new CommandLineParser(programParams);
            parser.Parse();

            if (programParams.Help)
            {
                Console.WriteLine(parser.UsageInfo.ToString(78, false));
            }
            else if (parser.HasErrors)
            {
                Console.WriteLine(parser.UsageInfo.ToString(78, true));
                return -1;
            }

            try
            {
                new Program(programParams);
            }
            catch (Exception e)
            {
                Log.Error(e.Message, e);
                Console.Out.WriteLine("ERROR: " + e.Message);
                return -1;
            }
            return 0;
        }


        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private ProgramParams AppParam { get; set; }

        private Program(ProgramParams appParams)
        {
            AppParam = appParams;
            Initialize();
        }

        private void Initialize()
        {
            if (AppParam.Verbose)
            {
                var repository = (Hierarchy) LogManager.GetRepository();
                var appender = new ConsoleAppender
                                   {
                                       Layout = new PatternLayout("%date %-5level  [%ndc] - %message%newline")
                                   };

                repository.Root.AddAppender(appender);
                repository.Configured = true;
                repository.RaiseConfigurationChanged(EventArgs.Empty);
                appender.Threshold = Level.Debug;
            }
            //MainCodeGoesHere

            if (AppParam.Run)
            {
                var file = string.IsNullOrEmpty(AppParam.File) ? "syno.xml" : AppParam.File;
                var profiles = AppParam.Profile.Count == 0 ? new List<String>() { "default" }: AppParam.Profile;
                using (NDC.Push(string.Format("{0}|{1}|", file, profiles)))
                {
                    try
                    {
                        if (!File.Exists(file))
                        {
                            throw new Exception(string.Format("File {0} does not exist", file));
                        }
                        var xmlReader = new Core.Xml.XmlReader();
                        Log.Info("Reading file");
                        var synoConfig = xmlReader.ReadFile(file);
                        var synoConfigProcessor = new SynoConfigProcessor();
                        Log.Info("Process report");
                        var dateTime = DateTime.Now;
                        foreach (var profile in profiles)
                        {
                            synoConfigProcessor.Run(synoConfig, profile);        
                        }
                        Log.Info(string.Format("Done [{0}]", DateTime.Now - dateTime));
                    }
                    catch (Exception e)
                    {
                        Console.Out.WriteLine(e.Message);
                        Log.Error(e.Message, e);
                    }
                }
            }
        }
        
        internal class ProgramException : Exception
        {
            public ProgramException()
            {
            }

            public ProgramException(string message)
                : base(message)
            {
            }

            public ProgramException(string message, Exception innerException)
                : base(message, innerException)
            {
            }
        }
    }
}